﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace MachineLearning {
    class DecisionTree {
        protected XmlToLinq _dataSet;
        protected IEnumerable<XElement> _trainingData = null;
        protected List<XName> _attributeList = null;
        protected XName _targetConcept = null;
        public readonly XName QUESTION = "Q";

        public DecisionTree() {}

        public DecisionTree(string fileName) {
            _dataSet = new XmlToLinq(fileName);
            _trainingData = _dataSet.Rows;
            XAttribute newAttribute = null;
            _attributeList = new List<XName>();
            _expressions = new List<string>();
            foreach (XAttribute a in _dataSet.SampleRowElement.Attributes()) {
                newAttribute = new XAttribute(a.Name, "");
                _attributeList.Add(a.Name);
            }
            _targetConcept = _attributeList[_attributeList.Count - 1];
            
        }

        double _pPositive = 0.0;
        public double getPercentPositive() {
            return _pPositive;
        }
        double _pNegative = 0.0;
        public double getPercentNegative() {
            return _pNegative;
        }

        protected List<string> _expressions = null;
        public string getExpression() {
            string exp = null;
            foreach (string s in _expressions) {
                exp += " or " + s;
            }
            return exp.Remove(0, 4);
        }

        //S collection of training examples
        public double Entropy(IEnumerable<XElement> S) {
            double entropy = 0.0;
            int positiveExamples = 0;
            int negativeExamples = 0;
            foreach (XElement e in S) {
                if ((string)e.Attribute(_targetConcept) == "Yes")
                    positiveExamples++;
                else negativeExamples++;
            }
            _pPositive = (double)positiveExamples 
                / (double)(positiveExamples + negativeExamples);
            _pNegative = 1.0 - _pPositive;
            if (_pPositive != 0.0 && _pNegative != 0.0) {
                entropy = (-1.0) * _pPositive * Math.Log(_pPositive, 2.0)
                    - _pNegative * Math.Log(_pNegative, 2.0);
            } else if (_pPositive != 0.0) {
                entropy = (-1.0) * _pPositive * Math.Log(_pPositive, 2.0);
            } else {
                entropy = (-1.0) * _pNegative * Math.Log(_pNegative, 2.0);
            }
            return entropy;
        }

        protected class Tree {
            List<Tree> _nodes;
            public List<Tree> Nodes {
                get { return _nodes;  }
            }

            XName _attribute;
            public XName getAttributeName() {
                return _attribute;
            }
            public void setAttributeName(XName name) {
                _attribute = name;
            }
            string _value;
            public string getAttributeValue() {
                return _value;
            }
            public void setAttributeValue(string value) {
                _value = value;
            }
            public Tree() {
                _nodes = new List<Tree>();
            }
        }
    }
}
